{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pong\n",
    "\n",
    "运行这个笔记本，看看会发生什么。\n",
    "\n",
    "一旦游戏画布出现，点击它使其获得焦点，然后使用箭头键、A键和D键控制挡板。\n",
    "\n",
    "* pong的声音来自[freesound](https://freesound.org/people/NoiseCollector/sounds/4359/).\n",
    "* Commodore 64字体来自[KreativeKorp](https://www.kreativekorp.com/software/fonts/c64.shtml)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "import sys\n",
    "import os\n",
    "\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sys.path.insert(0, os.path.abspath('./..'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import jupylet.color\n",
    "\n",
    "from jupylet.app import App\n",
    "from jupylet.state import State\n",
    "from jupylet.label import Label\n",
    "from jupylet.sprite import Sprite\n",
    "\n",
    "from jupylet.audio.sample import Sample"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "app = App()#log_level=logging.INFO)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "background = '#3e32a2'\n",
    "foreground = '#7c71da'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a0 = np.ones((32, 32)) * 255\n",
    "a1 = np.ones((128, 16)) * 255\n",
    "a2 = np.ones((app.height * 9 // 10, app.width * 9 // 10, 3)) * 255"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ball = Sprite(a0, y=app.height/2, x=app.width/2)\n",
    "\n",
    "padl = Sprite(a1, y=app.height/2, x=48)\n",
    "padr = Sprite(a1, y=app.height/2, x=app.width-48)\n",
    "\n",
    "field = Sprite(a2, y=app.height/2, x=app.width/2, color=background) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pong_sound = Sample('sounds/pong-blip.wav', amp=0.1).load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scorel = Label(\n",
    "    '0', font_size=42, color=foreground, \n",
    "    x=64, y=app.height/2, \n",
    "    anchor_y='center', anchor_x='left',\n",
    "    font_path='fonts/PetMe64.ttf'\n",
    ")\n",
    "\n",
    "scorer = Label(\n",
    "    '0', font_size=42, color=foreground, \n",
    "    x=app.width-64, y=app.height/2, \n",
    "    anchor_y='center', anchor_x='right',\n",
    "    font_path='fonts/PetMe64.ttf'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@app.event\n",
    "def render(ct, dt):\n",
    "    \n",
    "    app.window.clear(color=foreground)\n",
    "    \n",
    "    field.draw()\n",
    "    \n",
    "    scorel.draw()\n",
    "    scorer.draw()\n",
    "    \n",
    "    ball.draw()\n",
    "    padl.draw()\n",
    "    padr.draw()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "state = State(\n",
    "    \n",
    "    sl = 0,\n",
    "    sr = 0,\n",
    "    \n",
    "    bvx = 192,\n",
    "    bvy = 192,\n",
    "    \n",
    "    vyl = 0,\n",
    "    pyl = app.height/2,\n",
    "\n",
    "    vyr = 0,\n",
    "    pyr = app.height/2,\n",
    "\n",
    "    left = False,\n",
    "    right = False,\n",
    "\n",
    "    key_a = False,\n",
    "    key_d = False,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@app.event\n",
    "def key_event(key, action, modifiers):\n",
    "        \n",
    "    keys = app.window.keys\n",
    "    \n",
    "    if action == keys.ACTION_PRESS:\n",
    "        \n",
    "        if key == keys.LEFT:\n",
    "            state.left = True\n",
    "\n",
    "        if key == keys.RIGHT:\n",
    "            state.right = True\n",
    "\n",
    "        if key == keys.A:\n",
    "            state.key_a = True\n",
    "\n",
    "        if key == keys.D:\n",
    "            state.key_d = True\n",
    "\n",
    "    if action == keys.ACTION_RELEASE:\n",
    "\n",
    "    \n",
    "        if key == keys.LEFT:\n",
    "            state.left = False\n",
    "\n",
    "        if key == keys.RIGHT:\n",
    "            state.right = False\n",
    "\n",
    "        if key == keys.A:\n",
    "            state.key_a = False\n",
    "\n",
    "        if key == keys.D:\n",
    "            state.key_d = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@app.run_me_every(1/120)\n",
    "def update_pads(ct, dt):\n",
    "        \n",
    "    if state.right:\n",
    "        state.pyr = min(app.height, state.pyr + dt * 512)\n",
    "        \n",
    "    if state.left:\n",
    "        state.pyr = max(0, state.pyr - dt * 512)\n",
    "        \n",
    "    if state.key_a:\n",
    "        state.pyl = min(app.height, state.pyl + dt * 512)\n",
    "        \n",
    "    if state.key_d:\n",
    "        state.pyl = max(0, state.pyl - dt * 512)\n",
    "        \n",
    "    ayl = 200 * (state.pyl - padl.y)\n",
    "    ayr = 200 * (state.pyr - padr.y)\n",
    "\n",
    "    state.vyl = state.vyl * 0.9 + (ayl * dt)\n",
    "    state.vyr = state.vyr * 0.9 + (ayr * dt)\n",
    "    \n",
    "    padl.y += state.vyl * dt\n",
    "    padr.y += state.vyr * dt\n",
    "    \n",
    "    padr.clip_position(app.width, app.height)\n",
    "    padl.clip_position(app.width, app.height)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@app.run_me_every(1/60)\n",
    "def update_ball(ct, dt):\n",
    "    \n",
    "    bs0 = state.bvx ** 2 + state.bvy ** 2\n",
    "    \n",
    "    ball.angle += 200 * dt\n",
    "    \n",
    "    ball.x += state.bvx * dt\n",
    "    ball.y += state.bvy * dt\n",
    "    \n",
    "    if ball.top >= app.height:\n",
    "        pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "        ball.y -= ball.top - app.height\n",
    "        state.bvy = -state.bvy\n",
    "        \n",
    "    if ball.bottom <= 0:\n",
    "        pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "        ball.y -= ball.bottom\n",
    "        state.bvy = -state.bvy\n",
    "        \n",
    "    if ball.right >= app.width:\n",
    "        pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "        ball.x -= ball.right - app.width\n",
    "        \n",
    "        state.bvx = -192\n",
    "        state.bvy = 192 * np.sign(state.bvy)\n",
    "        bs0 = 0\n",
    "        \n",
    "        state.sl += 1\n",
    "        scorel.text = str(state.sl)\n",
    "        \n",
    "    if ball.left <= 0:\n",
    "        pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "        ball.x -= ball.left\n",
    "        \n",
    "        state.bvx = 192\n",
    "        state.bvy = 192 * np.sign(state.bvy)\n",
    "        bs0 = 0\n",
    "        \n",
    "        state.sr += 1\n",
    "        scorer.text = str(state.sr)\n",
    "        \n",
    "    if state.bvx > 0 and ball.top >= padr.bottom and padr.top >= ball.bottom: \n",
    "        if 0 < ball.right - padr.left < 10:\n",
    "            pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "            ball.x -= ball.right - padr.left\n",
    "            state.bvx = -state.bvx\n",
    "            state.bvy += state.vyr / 2\n",
    "            \n",
    "    if state.bvx < 0 and ball.top >= padl.bottom and padl.top >= ball.bottom: \n",
    "        if 0 < padl.right - ball.left < 10:\n",
    "            pong_sound.play(pan=2*max(.25, min(.75, ball.x / app.width))-1)\n",
    "            ball.x += ball.left - padl.right\n",
    "            state.bvx = -state.bvx\n",
    "            state.bvy += state.vyl / 2\n",
    "            \n",
    "    bs1 = state.bvx ** 2 + state.bvy ** 2\n",
    "    \n",
    "    if bs1 < 0.9 * bs0:\n",
    "        state.bvx = (bs0 - state.bvy ** 2) ** 0.5 * np.sign(state.bvx)\n",
    "\n",
    "    ball.wrap_position(app.width, app.height)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@app.run_me\n",
    "def highlights(ct, dt):\n",
    "    \n",
    "    sl0 = state.sl\n",
    "    sr0 = state.sr\n",
    "    \n",
    "    slc = np.array(scorel.color)\n",
    "    src = np.array(scorer.color)\n",
    "    \n",
    "    while True:\n",
    "        \n",
    "        ct, dt = yield 1/24\n",
    "        \n",
    "        r0 = 0.9 ** (120 * dt)\n",
    "        \n",
    "        scorel.color = np.array(scorel.color) * r0 + (1 - r0) * slc\n",
    "        scorer.color = np.array(scorer.color) * r0 + (1 - r0) * src\n",
    "        \n",
    "        if sl0 != state.sl:\n",
    "            sl0 = state.sl\n",
    "            scorel.color = 'white'\n",
    "\n",
    "        if sr0 != state.sr:\n",
    "            sr0 = state.sr\n",
    "            scorer.color = 'white'\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "7be0ecb0937c400a88ee5c525a899ee7": {
      "model_module": "ipyevents",
      "model_module_version": "1.7.1",
      "model_name": "EventModel",
      "state": {
       "_supported_key_events": [
        "keydown",
        "keyup"
       ],
       "_supported_mouse_events": [
        "click",
        "auxclick",
        "dblclick",
        "mouseenter",
        "mouseleave",
        "mousedown",
        "mouseup",
        "mousemove",
        "wheel",
        "contextmenu",
        "dragstart",
        "drag",
        "dragend",
        "dragenter",
        "dragover",
        "dragleave",
        "drop"
       ],
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "1.5.0",
       "source": "IPY_MODEL_f1482eef080c4ff0aa21e68747d8bd6c",
       "watched_events": [
        "keydown",
        "keyup",
        "click",
        "auxclick",
        "dblclick",
        "mouseenter",
        "mouseleave",
        "mousedown",
        "mouseup",
        "mousemove",
        "wheel",
        "contextmenu",
        "dragstart",
        "drag",
        "dragend",
        "dragenter",
        "dragover",
        "dragleave",
        "drop"
       ],
       "xy_coordinate_system": ""
      }
     },
     "cab7dfa426764cb0b960bfea7e9f815a": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "1.2.0",
      "model_name": "LayoutModel",
      "state": {}
     },
     "f1482eef080c4ff0aa21e68747d8bd6c": {
      "buffers": [
       {
        "data": "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KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA2fBX/ACM1p/wP/wBAavSq818Ff8jNaf8AA/8A0Bq9KqJbgFFFFIAooooAK818a/8AIzXf/AP/AEBa9KrzXxr/AMjNd/8AAP8A0BacdwMaiiirAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA2fBX/IzWn/A/wD0Bq9KrzXwV/yM1p/wP/0Bq9KqJbgFFFFIAooooAK818a/8jNd/wDAP/QFr0qvNfGv/IzXf/AP/QFpx3AxqKKKsAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDZ8Ff8AIzWn/A//AEBq9KrzXwV/yM1p/wAD/wDQGr0qoluAUUUUgCiiigArzXxr/wAjNd/8A/8AQFr0qvNfGv8AyM13/wAA/wDQFpx3AxqKKKsAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDZ8Ff8jNaf8D/APQGr0qvNfBX/IzWn/A//QGr0qoluAUUUUgCiiigArzXxr/yM13/AMA/9AWvSq818a/8jNd/8A/9AWnHcDGoooqwCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKANnwV/wAjNaf8D/8AQGr0qvNfBX/IzWn/AAP/ANAavSqiW4BRRRSAKKKKACvNfGv/ACM13/wD/wBAWvSq818a/wDIzXf/AAD/ANAWnHcDGoooqwCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKANnwV/yM1p/wP8A9AavSq818Ff8jNaf8D/9AavSqiW4BRRRSAKKKKACvNfGv/IzXf8AwD/0Ba9KrzXxr/yM13/wD/0BacdwMaiiirAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACvpf/hlT/qfP/KR/9ur5or9Lq+fz3HV8L7P2MrXvfReXcqKufNH/AAyp/wBT5/5SP/t1fNFfpdX5o0ZFjq+K9p7aV7WtovPsElY2fBX/ACM1p/wP/wBAavSq818Ff8jNaf8AA/8A0Bq9Kr3ZbkhRRRSAKKKKACvNfGv/ACM13/wD/wBAWvSq818a/wDIzXf/AAD/ANAWnHcDGoooqwCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAor3H4cfs7X/ivw5ba9ceLtMtbS9gjmtfscLXTcg70kyUCMpG0gFuQwOMc+0eGv2f/hpo2x5tLudYnjnEyS6hclsYxhCibY2XIzhlOckHI4ryMRnmEoNxu212X+diuVnxfpen3+q38dhpdjc313Lny4LaJpJHwCThVBJwAT9Aa9H8IfAb4j+IY1nfSotGt3RmSTVJDCSQ23aYwGkUnkjcoBAznkZ+1dL0+w0qwjsNLsbaxtIs+XBbRLHGmSScKoAGSSfqTVmvFr8S1ZaUoJeuv+Q+U/Na7t7i0uprS7glt7iF2jlilQq8bqcFWB5BBBBBqKvS/wBpvQf7B+MeseXafZ7bUdl/B+83+Z5g/eP1JGZRLwcY7DGK80r6zD1lWpRqLqkyQooorUQUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABX6XV+aNfpdXynE/wDy6/7e/QuIV+aNfpdX5o0cMf8AL3/t39QkbPgr/kZrT/gf/oDV6VXmvgr/AJGa0/4H/wCgNXpVfUS3ICiiikAU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",
        "encoding": "base64",
        "path": [
         "value"
        ]
       }
      ],
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "1.5.0",
      "model_name": "ImageModel",
      "state": {
       "_view_count": 1,
       "format": "JPEG",
       "layout": "IPY_MODEL_cab7dfa426764cb0b960bfea7e9f815a",
       "value": {}
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
